<?php
/**
 * 定义 Leaps 核心类，并初始化框架基本设置
 *
 * @author Tongle Xu <xutongle@gmail.com> 2013-9-5
 * @copyright Copyright (c) 2003-2103 tintsoft.com
 * @license http://www.tintsoft.com
 * @version $Id$
 */
if (PHP_VERSION < '5.2.0') die ( 'Require PHP > 5.2.0 !' );
defined ( 'APP_PATH' ) or die ( 'Undefined constant APP_PATH !' );
/**
 * 定义框架入口
 */
define ( 'IN_LEAPS', true );
/**
 * 定义框架版本
 */
define ( 'LEAPS_VERSION', '4.0.0' );
define ( 'LEAPS_RELEASE', '20130531S' );
/**
 * 定义开始时间
 */
defined ( 'START_TIME' ) or define ( 'START_TIME', microtime ( true ) );
/**
 * 定义内存占用
 */
define ( 'START_MEMORY', memory_get_usage () );
/**
 * 定义时间戳
 */
define ( 'TIME', time () );
/**
 * 定义框架路径
 */
defined ( 'FW_PATH' ) or define ( 'FW_PATH', dirname ( __FILE__ ) . DIRECTORY_SEPARATOR );
/**
 * DIRECTORY_SEPARATOR 的简写
 */
define ( 'DS', DIRECTORY_SEPARATOR );

defined ( 'LEAPS_DEBUG' ) or define ( 'LEAPS_DEBUG', false );
/**
 * 定义配置文件路径
 */
defined ( 'CONFIG_PATH' ) or define ( 'CONFIG_PATH', APP_PATH . 'config' . DIRECTORY_SEPARATOR );



Kernel::init ();

/**
 * 类 Kernel 是 Leaps 框架的核心类，提供了框架运行所需的基本服务
 *
 * @author Tongle Xu <xutongle@gmail.com>
 */
class Kernel {

	/**
	 * 对象注册表
	 *
	 * @var array
	 */
	private static $_objects = array ();
	public static $_imports = array ();

	/**
	 * 别名注册表
	 *
	 * @var array
	 */
	private static $_aliases = array ();

	/**
	 * 类搜索路径
	 *
	 * @var array
	 */
	private static $_includePaths = array ();

	/**
	 * 应用实例
	 */
	private static $_app;

	/**
	 * 核心初始化
	 */
	public static function init() {
		if (PHP_VERSION < '5.3.0') set_magic_quotes_runtime ( 0 );
		if (function_exists ( "set_time_limit" ) == TRUE and @ini_get ( "safe_mode" ) == 0) {
			@set_time_limit ( 300 );
		}
		if (! function_exists ( 'spl_autoload_register' )) {
			throw new Exception ( 'spl_autoload does not exist in this PHP installation' );
		}
		spl_autoload_register ( array ('Kernel','autoload' ) );
		self::setPathOfAlias(FW_PATH,'FW',true);
	}

	/**
	 * 创建Web应用程序
	 *
	 * @param string $config 配置，它可能是一个字符串或数组
	 * @return mixed 创建后的对象
	 */
	public static function createWebApplication($config = null) {
		return self::createApplication ( 'Web_Application', $config );
	}

	/**
	 * 创建Api应用程序
	 *
	 * @param string $config 配置，它可能是一个字符串或数组
	 * @return mixed 创建后的对象
	 */
	public static function createApiApplication($config = null) {
		return self::createApplication ( 'Api_Application', $config );
	}

	/**
	 * 创建控制台应用程序
	 *
	 * @param string $config 配置，它可能是一个字符串或数组
	 * @return mixed 创建后的对象
	 */
	public static function createConsoleApplication($config = null) {
		return self::createApplication ( 'Console_Application', $config );
	}

	/**
	 * 创建应用程序实例
	 *
	 * @param string $class 应用程序类名
	 * @param mixed $config 应用程序配置。 这个参数将会传递给应用程序类的构造函数
	 * @return mixed 这个应用程序实例
	 */
	public static function createApplication($class, $config = null) {
		return new $class ( $config );
	}

	/**
	 * 获取应用实例
	 */
	public static function getApp() {
		return self::$_app;
	}

	/**
	 * 设置应用
	 *
	 * @param unknown $app
	 * @throws Exception
	 */
	public static function setApp($app) {
		if (self::$_app === null || $app === null)
			self::$_app = $app;
		else
			throw new Exception ( 'Leaps application can only be created once.' );
	}

	/**
	 * 类自动加载器
	 *
	 * @param string $className 类名
	 * @return boolean 是否该类已经被成功载入
	 */
	public static function autoLoad($className) {
		if (($pos = strrpos ( $className, '_' )) !== false) { // Leaps核心类
			$fileName = str_replace ( '_', DIRECTORY_SEPARATOR, $className );
		} else
			$fileName = $className;
		$classFile = $fileName . '.php';
		include $classFile;
		return class_exists ( $className, false ) || interface_exists ( $className, false );
	}

	/**
	 * 加载一个类
	 * 参数格式说明：'FW:Base.Controller'
	 * FW 注册的应用名称，应用名称与路径信息用‘:’号分隔
	 * Base.Controller 相对的路径信息
	 * 如果不填写应用名称 ，例如‘Base.Controller’，那么加载路径则相对于默认的应用路径
	 *
	 * @param string $alias 文件路径信息 或者className
	 * @return string null
	 */
	public static function import($alias) {
		if (isset ( self::$_imports [$alias] )) {
			return self::$_imports [$alias];
		}
		if (class_exists ( $alias, false ) || interface_exists ( $alias, false )) {
			return self::$_imports [$alias] = $alias;
		}
		if (($pos = strrpos ( $alias, '.' )) !== false) { // 含有点
			$className = substr ( $alias, $pos + 1 );
		} elseif (($pos = strrpos ( $alias, ':' )) !== false) { // 含有应用名称
			$className = substr ( $alias, $pos + 1 );
		} else {
			$className = $alias;
		}
		if (($path = self::getRealPath ( $alias )) !== false) {
			if (is_file ( $path . '.php' )) {
				include ($path . '.php');
				//大小写匹配
				//if (LEAPS_DEBUG && basename ( realpath ( $classFile ) ) != basename ( $classFile )) {
				//	throw new Exception ( 'Class name "' . $classFile . '" does not match class file "' . $classFile . '".' );
				//}
			} else {
				throw new Exception ( 'Alias "' . $alias . '" is invalid. Make sure it points to an existing PHP file and the file is readable.' );
			}
			return $className;
		} else {
			throw new Exception ( 'Alias "' . $alias . '" is invalid. Make sure it points to an existing directory or file.' );
		}
	}

	/**
	 * 解析别名路径信息
	 *
	 * @param string $alias
	 * @return string
	 */
	public static function getRealPath($alias) {
		if (($pos = strpos ( $alias, ':' )) !== false) {
			$rootAlias = self::getPathOfAlias ( substr ( $alias, 0, $pos ) ). DIRECTORY_SEPARATOR;
			$alias = substr ( $alias, $pos + 1 );
		} else
			$rootAlias = FW_PATH;

		$filePath = str_replace ( '.', DIRECTORY_SEPARATOR, $alias );
		return $rootAlias . $filePath;
	}

	/**
	 * 创建组件实例
	 *
	 * @param unknown $config
	 * @throws Exception
	 * @return unknown
	 */
	public static function createComponent($config) {
		if (is_string ( $config )) {
			$className = $config;
			$config = array ();
		} elseif (isset ( $config ['class'] )) {
			$className = $config ['class'];
			unset ( $config ['class'] );
		} else
			throw new Exception ( 'Object configuration must be an array containing a "class" element.' );

		if (($n = func_num_args ()) > 1) {
			$args = func_get_args ();
			if ($n === 2)
				$object = new $className ( $args [1] );
			elseif ($n === 3)
				$object = new $className ( $args [1], $args [2] );
			elseif ($n === 4)
				$object = new $className ( $args [1], $args [2], $args [3] );
			else {
				unset ( $args [0] );
				$class = new ReflectionClass ( $className );
				$object = call_user_func_array ( array ($class,'newInstance' ), $args );
			}
		} else
			$object = new $className ();

		foreach ( $config as $key => $value )
			$object->$key = $value;
		return $object;
	}

	/**
	 * 创建类的实例
	 * @param unknown $className 类名
	 * @param unknown $args 配置
	 * @throws Exception
	 * @return mixed
	 */
	public static function createInstance($className, $args = array()) {
		try {
			if (empty($args)) {
				return new $className();
			} else {
				$reflection = new ReflectionClass($className);
				return call_user_func_array(array($reflection, 'newInstance'), (array) $args);
			}
		} catch (Exception $e) {
			throw new Exception('Create instance \'' . $className . '\' fail.' . $e->getMessage());
		}
	}

	/**
	 * 获取类实例
	 *
	 * @param string $className 类名
	 * @param array $args 参数
	 */
	public static function getInstance($className, array $args = array()) {
		try {
			$key = empty ( $args ) ? $className : $className . to_guid_string ( $args );
			if (! empty ( $args )) {
				$args ['class'] = $className;
			}
			self::$_objects [$key] = self::createInstance ( $className );
			return self::$_objects [$key];
		} catch ( Exception $e ) {
			throw new Base_Exception ( '[Core.get_instance] create instance \'' . $className . '\' fail.' . $e->getMessage () );
		}
	}

	/**
	 * 将路径信息注册到命名空间,该方法不会覆盖已经定义过的命名空间
	 *
	 * @param string $path 需要注册的路径
	 * @param string $alias 路径别名
	 * @param boolean $includePath | 是否同时定义includePath
	 * @param boolean $reset | 是否覆盖已经存在的定义，默认false
	 * @return void
	 * @throws Exception
	 */
	public static function setPathOfAlias($path = '', $alias, $includePath = false, $reset = false) {
		if (! empty ( $alias )) {
			if (! isset ( self::$_aliases [$alias] ) || $reset) {
				self::$_aliases [$alias] = rtrim ( $path, '\\/' );
			}
		}
		if ($includePath) {
			if (empty ( self::$_includePaths )) {
				self::$_includePaths = array_unique ( explode ( PATH_SEPARATOR, get_include_path () ) );
				if (($pos = array_search ( '.', self::$_includePaths, true )) !== false) unset ( self::$_includePaths [$pos] );
			}
			array_unshift ( self::$_includePaths, $path );
			if (set_include_path ( '.' . PATH_SEPARATOR . implode ( PATH_SEPARATOR, self::$_includePaths ) ) === false) {
				throw new Exception ( '[Kernel.register] set include path error.' );
			}
		}
	}

	/**
	 * 返回命名空间的路径信息
	 *
	 * @param string $alias
	 * @return Ambigous <string, multitype:>
	 */
	public static function getPathOfAlias($alias) {
		return isset ( self::$_aliases [$alias] ) ? self::$_aliases [$alias] : false;
	}

	/**
	 * 获取debug对象
	 * 可安全用于生产环境，在生产环境下将忽略所有debug信息
	 *
	 * @return Debug
	 */
	public static function debug() {
		if(LEAPS_DEBUG){
			return self::getInstance('Debug');
		}
		return self::getInstance('NoDebug');
	}
}

/**
 * 基类
 *
 * @author Tongle Xu
 *
 */
class Object {
	public function __construct() {
	}
	public function __get($name) {
		return isset ( $this->$name ) ? $this->$name : null;
	}
	public function __set($name, $value) {
		$this->$name = $value;
	}
	public function __isset($name) {
		return isset ( $this->$name );
	}
	public function __unset($name) {
		unset ( $this->$name );
	}
	public function __toString() {
		return get_class ( $this );
	}
}

/**
 * 配置文件管理类
 *
 * @author Tongle Xu <xutongle@gmail.com> 2013-9-14
 * @copyright Copyright (c) 2003-2103 tintsoft.com
 * @license http://www.tintsoft.com
 * @version $Id$
 */
class Config {

	/**
	 * 所有的配置数组
	 *
	 * @var array
	 */
	public static $items = array ();

	/**
	 * 配置解析缓存
	 *
	 * @var array
	 */
	public static $cache = array ();

	/**
	 * 确定一个配置项或文件是否存在
	 *
	 * <code>
	 * // Determine if the "session" configuration file exists
	 * $exists = Config::has('session');
	 *
	 * // Determine if the "timezone" option exists in the configuration
	 * $exists = Config::has('application.timezone');
	 * </code>
	 *
	 * @param string $key
	 * @return bool
	 */
	public static function has($key) {
		return ! is_null ( self::get ( $key ) );
	}

	/**
	 * 获取配置项
	 *
	 * <code>
	 * // Get the "session" configuration array
	 * $session = Config::get('session');
	 *
	 * // Get the "timezone" option from the "application" configuration file
	 * $timezone = Config::get('application.timezone');
	 * </code>
	 *
	 * @param string $key 键名
	 * @param string $default 默认值
	 */
	public static function get($key, $default = null) {
		list ( $file, $item ) = self::parse ( $key );
		if (! self::load ( $file )) return $default;
		$items = self::$items [$file];
		if (is_null ( $item )) {
			return $items;
		} else {
			return isset ( $items [$item] ) ? $items [$item] : $default;
		}
	}

	/**
	 * 修改配置(运行时)
	 *
	 * @param string $file 配置文件名称
	 * @param string $key 配置项
	 * @param $default 默认值
	 */
	public static function set($key, $value) {
		list ( $file, $item ) = self::parse ( $key );
		self::load ( $file );
		self::$items [$file] [$item] = $value;
	}

	/**
	 * 修改配置文件
	 *
	 * @param $file 文件名称
	 * @param $data 配置数组
	 */
	public static function modify($file, $data = array()) {
		if (! is_writable ( self::path ( $file ) )) {
			return false;
		}
		$pattern = $replacement = array ();
		foreach ( $data as $k => $v ) {
			$v = trim ( $v );
			$configs [$k] = $v;
			$pattern [$k] = "/'" . $k . "'\s*=>\s*([']?)[^']*([']?)(\s*),/is";
			$replacement [$k] = "'" . $k . "' => \${1}" . $v . "\${2}\${3},";
		}
		$str = @file_get_contents ( self::path ( $file ) );
		$str = preg_replace ( $pattern, $replacement, $str );
		return @file_put_contents ( self::path ( $file ), $str );
	}

	/**
	 * 创建配置文件
	 *
	 * @param string $file 文件名称
	 * @param array $data 配置数组
	 */
	public static function create($file, $array = array()) {
		$data = "<?php\nreturn " . var_export ( $array, true ) . ';';
		if (! file_put_contents ( self::path ( $file ), $data )) {
			return false;
		}
		return true;
	}

	/**
	 * 解析
	 *
	 * @param string $key
	 * @return multitype:
	 */
	private static function parse($key) {
		if (array_key_exists ( $key, self::$cache )) {
			return self::$cache [$key];
		}
		$segments = explode ( '.', $key );
		if (count ( $segments ) >= 2) {
			$parsed = array ($segments [0],implode ( '.', array_slice ( $segments, 1 ) ) );
		} else {
			$parsed = array ($segments [0],null );
		}
		return self::$cache [$key] = $parsed;
	}

	/**
	 * 加载配置文件
	 *
	 * @param string $file
	 * @return boolean
	 */
	public static function load($file) {
		if (isset ( self::$items [$file] )) return true;
		if (file_exists ( self::path ( $file ) )) {
			self::$items [$file] = include self::path ( $file );
		} else {
			return false;
		}
		return isset ( self::$items [$file] );
	}

	/**
	 * 返回配置文件绝对路径
	 *
	 * @param string $file
	 * @return string
	 */
	protected static function path($file) {
		return CONFIG_PATH . $file . '.php';
	}
}

/**
 * /**
 * 核心Debug类
 * 支持新浪Sae 和百度Bae 在线调试
 */
class Debug extends FB {

	/**
	 * 开启Xhprof调试信息
	 */
	public function xhprof_start($type = null) {
		if (function_exists ( 'saeAutoLoader' )) {
			sae_xhprof_start ();
			return;
		}
		if (function_exists ( 'baexhprof_start' )) {
			baexhprof_start ();
			return;
		}
		$profiler = $this->profiler ( 'xhprof' );
		if (true === $profiler->is_open ()) {
			$xhprof_fun = 'xhprof_enable';
			if (function_exists ( $xhprof_fun )) {
				$xhprof_fun ( $type );
			}
			$profiler->start ( 'Xhprof', $type === null ? 'default' : 'Type:' . $type );
		}
	}

	/**
	 * 停止Xhprof调试信息
	 */
	public function xhprof_stop() {
		if (function_exists ( 'saeAutoLoader' )) {
			sae_xhprof_end ();
			return;
		}
		if (function_exists ( 'baexhprof_end' )) {
			baexhprof_end ();
			return;
		}
		$profiler = $this->profiler ( 'xhprof' );
		if (true === $profiler->is_open ()) {
			$xhprof_fun = 'xhprof_disable';
			if (function_exists ( $xhprof_fun )) {
				$data = $xhprof_fun ();
			} else {
				$data = null;
			}
			$profiler->stop ();
			return $data;
		}
	}
	public function __call($m, $v) {
		return $this;
	}
}

class NoDebug {
	public function __call($m, $v) {
		return $this;
	}
	public function log($i = null) {
		return $this;
	}
	public function info($i = null) {
		return $this;
	}
	public function error($i = null) {
		return $this;
	}
	public function group($i = null) {
		return $this;
	}
	public function groupEnd($i = null) {
		return $this;
	}
	public function table($Label = null, $Table = null) {
		return $this;
	}
	public function profiler($i = null) {
		return $this;
	}
	public function is_open() {
		return false;
	}
}

/**
 * 加载配置文件
 *
 * @param string $key 文件名配置项
 * @param string/bool $default 默认值
 */
function C($key, $default = null) {
	return Config::get ( $key, $default );
}

/**
 * 载入文件
 *
 * @param string $name 文件名称 或带路径的文件名称
 */
function import($name) {
	return Kernel::import ( $name );
}

/**
 * 设置和获取统计数据
 *
 * @param string $key 要统计的项
 * @param int $step 递加的值
 * @return int 如果递加的值为空返回目前该项统计到的次数
 */
function N($key, $step = 0) {
	static $_num = array ();
	if (! isset ( $_num [$key] )) {
		$_num [$key] = 0;
	}
	if (empty ( $step ))
		return $_num [$key];
	else
		$_num [$key] = $_num [$key] + ( int ) $step;
}

/**
 * 记录加载和运行时间
 *
 * @param string $start
 * @param string $end
 * @param int $dec
 */
function G($start, $end = '', $dec = 3) {
	static $_info = array ();
	if (! empty ( $end )) { // 统计时间
		if (! isset ( $_info [$end] )) $_info [$end] = microtime ( TRUE );
		return number_format ( ($_info [$end] - $_info [$start]), $dec );
	} else { // 记录时间
		$_info [$start] = microtime ( TRUE );
	}
}

/**
 * 全局缓存读取、设置、删除，默认为文件缓存。
 *
 * @param string $key 缓存名称
 * @param string $value 缓存内容
 * @param int $expires 缓存有效期
 */
function S($key, $value = null, $expires = 0) {
	if (is_null ( $value )) { // 获取缓存
		return Factory::getComponent ( 'cache' )->get ( $key );
	} elseif ($value === '') { // 删除缓存
		return Factory::getComponent ( 'cache' )->delete ( $key );
	} else {
		return Factory::getComponent ( 'cache' )->set ( $key, $value, $expires );
	}
}

/**
 * 浏览器友好的变量输出
 *
 * @param mixed $var 变量
 * @param boolean $echo 是否输出 默认为True 如果为false 则返回输出字符串
 * @param string $label 标签 默认为空
 * @param boolean $strict 是否严谨 默认为true
 * @return void string
 */
function dump($var, $echo = true, $label = null, $strict = true) {
	$label = ($label === null) ? '' : rtrim ( $label ) . ' ';
	if (! $strict) {
		if (ini_get ( 'html_errors' )) {
			$output = print_r ( $var, true );
			$output = '<pre>' . $label . htmlspecialchars ( $output, ENT_QUOTES ) . '</pre>';
		} else {
			$output = $label . print_r ( $var, true );
		}
	} else {
		ob_start ();
		var_dump ( $var );
		$output = ob_get_clean ();
		if (! extension_loaded ( 'xdebug' )) {
			$output = preg_replace ( '/\]\=\>\n(\s+)/m', '] => ', $output );
			$output = '<pre>' . $label . htmlspecialchars ( $output, ENT_QUOTES ) . '</pre>';
		}
	}
	if ($echo) {
		echo ($output);
		return null;
	} else
		return $output;
}
/**
 * 根据PHP各种类型变量生成唯一标识号
 *
 * @param mixed $mix 变量
 * @return string
 */
function to_guid_string($mix) {
	if (is_object ( $mix ) && function_exists ( 'spl_object_hash' )) {
		return spl_object_hash ( $mix );
	} elseif (is_resource ( $mix )) {
		$mix = get_resource_type ( $mix ) . strval ( $mix );
	} else {
		$mix = serialize ( $mix );
	}
	return md5 ( $mix );
}